home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / SciAn / src / ScianFileSystem.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  41KB  |  1,399 lines

  1. /*    ScianFileSystem.c
  2.     manages file system window for scian
  3.  
  4.     Jim Lyons
  5.     created 4/17/91
  6.  
  7.     4/28/91 version 2 of files window
  8.     5/1/91  version 3: made file objects
  9.     5/3/91    added format dialog routines
  10.     5/29/91 EMP removed lib headers
  11.     6/25/91 removed icon definitions
  12.     7/22/91 added Read Data Files menu item
  13.     8/8/91    guarded all strcpy and strcat calls
  14.     9/9/91    added help strings
  15.     9/16/91    redesigned file window
  16.     9/19/91 added file info window
  17.     10/12/91 removed Set File Type stuff
  18.     10/28/91 changed interface to File Readers (with EMP)
  19.     1/20/92    changed order of file type identification in ReadDir
  20.     2/5/92    added DropInContents method to file window corral
  21.     4/8/92    made all chdirs temporary, never change dirs on user
  22.     4/17/92    changed Open to use Object Function
  23.     4/23/92 changed Set Format and Show Info to use Object Functions
  24.     5/26/92 EMP fixed OpenParent not to fail at root
  25.     5/26/92 EMP made GetFileWindow public
  26.     6/13/92 EMP changed to use method declarations, not prototypes
  27.     10/15/92 Modified file info window to make two-line directory name
  28.     2/3/93    Fixed bug in file info routine
  29. */
  30.  
  31. #include "Scian.h"
  32. #ifdef GETPWNAM
  33. #include <pwd.h>
  34. #endif
  35. #include "ScianStyle.h"
  36. #include "ScianTypes.h"
  37. #include "ScianMethods.h"
  38. #include "ScianArrays.h"
  39. #include "ScianFontSystem.h"
  40. #include "ScianWindows.h"
  41. #include "ScianTextBoxes.h"
  42. #include "ScianSliders.h"
  43. #include "ScianButtons.h"
  44. #include "ScianTitleBoxes.h"
  45. #include "ScianObjWindows.h"
  46. #include "ScianObjFunctions.h"
  47. #include "ScianDatabase.h"
  48. #include "ScianSymbols.h"
  49. #include "ScianColors.h"
  50. #include "ScianControls.h"
  51. #include "ScianTimers.h"
  52. #include "ScianLists.h"
  53. #include "ScianIDs.h"
  54. #include "ScianEvents.h"
  55. #include "ScianErrors.h"
  56. #include "ScianDialogs.h"
  57. #include "ScianIcons.h"
  58. #include "ScianFiles.h"
  59. #include "ScianDatasets.h"
  60. #include "ScianScripts.h"
  61. #include "ScianPreferences.h"
  62. #include "ScianFileSystem.h"
  63.  
  64. /* defs for file window parameters */
  65.  
  66. #undef TITLEBOXTOP
  67. #define TITLEBOXTOP    14
  68.  
  69. #define PARENTBTNWID    104
  70. #define PARENTBTNHT    70
  71. #define MINBTNWID    120
  72. #define FILTERBTNWID    218
  73.  
  74. #define FILESWIDTH    (2*MINORBORDER + 2*SMALLGAP + 3*MINBTNWID)
  75. #define FILESHEIGHT    390
  76.  
  77.  
  78. /* defs for file format dialog box */
  79. #define RADIOWID    84
  80. #define BOTPART        (BOTMARGIN + OKBTNHT + INTERSPACE)
  81.  
  82. #define STICKYALL    (STICKYRIGHT + STICKYLEFT + STICKYBOTTOM + STICKYTOP)
  83.  
  84. /* defs for file info window */
  85. #define NINFOITEMS    5
  86. #define INFOITEMHT    40
  87. #define INFOITEMWID    110
  88. #define INFONAMEWIDTH    70
  89. #define INFOFIELDWIDTH    200
  90. #define INFOFIELDHEIGHT    (NINFOITEMS*INFOITEMHT)
  91. #define INFOWIDTH    (3*MINORBORDER + INFONAMEWIDTH + INFOFIELDWIDTH)
  92. #define INFOHEIGHT    \
  93.     (MINORBORDER + MAJORBORDER + GAP + 2*INFOFONTSIZE + 2*DEFLINESPACE + BARWIDTH + INFOFIELDHEIGHT)
  94. #define INFOFONT    "Helvetica-Bold"
  95. #define INFOFONTSIZE    12
  96.  
  97. /* file selector bit mask */
  98. #define MASK(f)        (1<<f)
  99.  
  100. #define DEFAULTFILTER    (MASK(DIRFILE) | MASK(DATAFILE) | MASK(LOGFILE) | MASK(PALFILE))
  101. #define ALLFILES    (MASK(NFILETYPES) - 1)
  102.  
  103. /* EMP static method declarations */
  104.  
  105. static ObjPtr CancelDialog();
  106. static ObjPtr OKDialog();
  107. static ObjPtr DoParent();
  108. static ObjPtr DropInFileWin();
  109. static ObjPtr OpenParent();
  110. static ObjPtr OpenFile();
  111. static ObjPtr OpenFolder();
  112. static ObjPtr NewFilter();
  113. static ObjPtr ShowFiles();
  114.  
  115.  
  116. /* static function prototypes */
  117. #ifdef PROTO
  118.  
  119. static ObjPtr SetFormat(ObjPtr);
  120. static ObjPtr ShowInfo(ObjPtr);
  121. static char *GetFileInfo(char *, char *);
  122. static void FileFormatDialog(FuncTyp);
  123. static ObjPtr OKFormat(int, ObjPtr);
  124. static void ChangeFileType(ObjPtr, int);
  125. static ObjPtr SelFileList(ObjPtr);
  126. static ObjPtr SelDirList(ObjPtr);
  127. static ObjPtr NewFileWindow(WinInfoPtr, char *);
  128. static Bool ReadDirectory(ObjPtr);
  129. static int FileType(char *);
  130.  
  131. #else
  132.  
  133. static ObjPtr SetFormat();
  134. static ObjPtr ShowInfo();
  135. static char *GetFileInfo();
  136. static void FileFormatDialog();
  137. static ObjPtr OKFormat();
  138. static void ChangeFileType();
  139. static ObjPtr SelFileList();
  140. static ObjPtr SelDirList();
  141. static ObjPtr NewFileWindow();
  142. static Bool ReadDirectory();
  143. static int FileType();
  144.  
  145. #endif
  146.  
  147. /********************************************************* GLOBALS */
  148.  
  149. int fileIcon[NFILETYPES] = {ICONFOLDER, ICONBINFILE, ICONOBJFILE, ICONTEXTFILE,
  150.                 ICONDATAFILE, ICONSCIANDOC, ICONCTABLE, ICONUNKNOWN};
  151. char *fileTypeName[NFILETYPES] = {"Dir", "Bin", "Obj", "Text", "Data", 
  152.             "SciAn Log", "Palette", "Other"};
  153.  
  154. char dirSave[MAXPATHLEN+1];    /* save original working directory name */
  155. char replySave[MAXPATHLEN+1];    /* keep dialog reply text for reediting */
  156.  
  157. ObjPtr aList;    /* list for collecting selected files */
  158.  
  159.  
  160. /********************************************************** INIT FILE SYSTEM */
  161. void InitFileSystem(void)
  162. {
  163.     /* (fileClass is handled by ScianFiles) */
  164.     /* ...but set the object function here for double clicking per EMP */
  165.  
  166.     SetVar(fileClass, DOUBLECLICK, NewString(OF_OPEN));
  167.  
  168.     getwd(dirSave);        /* save original working directory name */
  169.     *replySave = '\0';    /* clear saved path */
  170. }
  171.  
  172. void KillFileSystem(void)
  173. {
  174.     /* (fileClass is handled by ScianFiles) */
  175.  
  176. }
  177.  
  178. /******************************************************* OBJ FUNCTION ROUTINES */
  179. #ifdef PROTO
  180. ObjPtr Collect(ObjPtr theFile)
  181. #else
  182. ObjPtr Collect(theFile)
  183. ObjPtr theFile;
  184. #endif
  185. /* used as method for collecting files to Set Format or Show Info */
  186. {
  187.     PrefixList(aList, theFile);
  188.     return ObjTrue;
  189. }
  190.  
  191. void SetUpCollect()
  192. /* setup routine for Set Format and Show Info */
  193. {
  194.     aList = NewList();
  195. }
  196.  
  197. void RestoreDir()
  198. /* restores original directory after opening files */
  199. {
  200.     chdir(dirSave);
  201. }
  202.  
  203. /******************************************************* DO NEW FILE WINDOW */
  204. void DoNewFileWindow(void)
  205. /* New File Window menu routine */
  206. {
  207.     WinInfoPtr askWindow;
  208.  
  209.     if (logging)
  210.     {
  211.         Log("Show FilesWindow\n");
  212.         InhibitLogging(true);
  213.     }
  214.     if (*replySave)
  215.     {
  216.         strncpy(tempStr, replySave, TEMPSTRSIZE);
  217.         tempStr[TEMPSTRSIZE] = '\0';
  218.     }
  219.     else if (PrefExists(PREF_DEFDIR))
  220.     {
  221.         strncpy(tempStr, GetPrefString(PREF_DEFDIR), TEMPSTRSIZE);
  222.         tempStr[TEMPSTRSIZE-1] = '\0';
  223.     }
  224.     else getwd(tempStr);
  225.     askWindow = AskUser((WinInfoPtr) NULLOBJ, "Enter directory name:",
  226.          (FuncTyp) NewFileWindow, tempStr);
  227.     if (askWindow) SetVar((ObjPtr) askWindow, HELPSTRING, NewString("This dialog window \
  228. allows you to enter the name of the directory for which you want to open a new File Window. \
  229. The default directory name, showing when the window first comes up, may be set in the \
  230. Preferences window."));
  231.     if (logging) InhibitLogging(false);
  232. }
  233.  
  234. static ObjPtr NewFileAgain(WinInfoPtr win, int n)
  235. /* called if error in directory name from New File Window dialog */
  236. {
  237.     if (n == 1) DoNewFileWindow();
  238.     else *replySave = '\0'; /* clear error string */
  239.     return NULLOBJ;
  240. }
  241.  
  242. #define MAXUSERNAME    20    /*Max # of chars in user name*/
  243.  
  244. #ifdef PROTO
  245. static ObjPtr NewFileWindow(WinInfoPtr owner, char *replyText)
  246. #else
  247. static ObjPtr NewFileWindow(owner, replyText)
  248. WinInfoPtr owner;
  249. char *replyText;
  250. #endif
  251. /* puts up the New File Window */
  252. {
  253.     char *s, t[MAXPATHLEN + 1];
  254.     WinInfoPtr alert;
  255.     DIR *dirp;
  256.  
  257.     SKIPBLANKS(replyText);
  258.     if (*replyText == '~')
  259.     {
  260.         /*See if next character could be a name*/
  261.         if (isdigit(replyText[1]) || isalpha(replyText[1]))
  262.         {
  263.         /*Must be some nother user*/
  264. #ifdef GETPWNAM
  265.         int k;
  266.         struct passwd *pwdEntry;
  267.         char userName[MAXUSERNAME + 1];
  268.  
  269.         for (k = 1;
  270.              k < MAXUSERNAME && (isdigit(replyText[k]) || isalpha(replyText[k]));
  271.              ++k)
  272.         {
  273.             userName[k-1] = replyText[k];
  274.         }
  275.         userName[k-1] = '\0';
  276.  
  277.         pwdEntry = getpwnam(userName);
  278.         if (pwdEntry)
  279.         {
  280.             /*Entry's OK*/
  281.             strcpy(t, pwdEntry -> pw_dir);
  282.             strcat(t, replyText + k);
  283.         }
  284.         else
  285.         {
  286.             /* unknown user */
  287.             strcpy(replySave, replyText); /* save text for user reediting */
  288.             sprintf(t, "Unknown user, %s.", userName);
  289.             alert = AlertUser(UIERRORALERT, owner, t,
  290.                 NewFileAgain, 2, "Cancel", "Re-enter");
  291.             if (alert) SetVar((ObjPtr) alert, HELPSTRING, NewString("You have used the \
  292. '~user' construct in a directory name to find another user's home directory.  \
  293. No user with the specified name could be found.  Press \
  294. the Re-enter button to correct the entry, or press the Cancel key to cancel the request."));
  295.             return ObjTrue;
  296.         }
  297. #else
  298.         /* save text for user reediting */
  299.         strcpy(replySave, replyText);
  300.  
  301.         alert = AlertUser(UIERRORALERT, owner, "Sorry, this version of SciAn does not \
  302. support the '~user' construct in a directory name.", NewFileAgain,
  303.                 2, "Cancel", "Re-enter");
  304.         if (alert) SetVar((ObjPtr) alert, HELPSTRING, NewString("You have used the \
  305. '~user' construct in a directory name to find a user's home directory.  This \
  306. version of SciAn has not been compiled to accept this construct.  Press \
  307. the Re-enter button to correct the entry, or press the Cancel key to cancel the request."));
  308.         return ObjTrue;
  309. #endif
  310.         }
  311.         else
  312.         {
  313.         if (s = getenv("HOME")) /* substitute for squiggle */
  314.         {
  315.             strcpy(t, s);
  316.             strcat(t, replyText + 1);
  317.         }
  318.         }
  319.     }
  320.     else if (*replyText)
  321.     {
  322.         strcpy(t, replyText);
  323.     }
  324.     else
  325.     {
  326.         t[0] = '/';
  327.         t[1] = '\0';
  328.     }
  329.  
  330.     if (chdir(t) == 0) /* check if valid directory */
  331.     {
  332.         getwd(t);    /* get expanded name back */
  333.         GetFileWindow(t);
  334.         *replySave = '\0'; /* clear error string */
  335.         chdir(dirSave);    /* return to original directory */
  336.         return ObjTrue;
  337.     }
  338.     else /* error */
  339.     {
  340. #define PROMPT1 "Could not open directory "
  341. #define PROMPT2 ". Do you want to enter another directory or cancel the request?"
  342.  
  343.         /* save text for user reediting */
  344.         strcpy(replySave, replyText);
  345.  
  346.         /* set up prompt in tempStr */
  347.         strcpy(tempStr, PROMPT1);
  348.         strncat(tempStr, (t ? t : replyText), 
  349.             TEMPSTRSIZE - strlen(PROMPT1) - strlen(PROMPT2) - 1);
  350.         strcat(tempStr, PROMPT2);
  351.         alert = AlertUser(UIERRORALERT, owner, tempStr, NewFileAgain,
  352.                 2, "Cancel", "Re-enter");
  353.         if (alert) SetVar((ObjPtr) alert, HELPSTRING, NewString("This dialog window \
  354. came up because the directory entered in the New File Window dialog could not be opened. Press \
  355. the Re-enter button to correct that entry, or press the Cancel key to cancel the request."));
  356.         
  357.     }
  358.     return ObjTrue;
  359. }
  360.  
  361. /******************************************************* SET FORMAT */
  362. void ProcessSetFormat(void)
  363. {
  364.     ObjPtr corral;
  365.     int fmt, i,n;
  366.  
  367.     if (!selWinInfo || !(corral = GetVar((ObjPtr) selWinInfo, CORRAL))
  368.         || ListCount(aList) == 0) return;
  369.  
  370.     /* now make dialog */
  371.     FileFormatDialog(OKFormat);
  372.  
  373.     /*** assuming selWinInfo is now the new dialog ... */
  374.     SetVar((ObjPtr) selWinInfo, FILELIST, aList); /* stash file list with dialog */
  375.  
  376.     if (logging) InhibitLogging(false);
  377.     return;
  378. }
  379.  
  380. static ObjPtr OKFormat(int fmt, ObjPtr list)
  381. {
  382.     ObjPtr theFile, theRdr, theIcon, keyList, fileReaders;
  383.     int i, n = ListCount(list);
  384.  
  385.     /* make a list of all the file readers */
  386.     keyList = NewList();
  387.     PostfixList(keyList, NewSymbol(CLASSID));
  388.     PostfixList(keyList, NewInt(CLASS_FILEREADER));
  389.     fileReaders = SearchDatabase(keyList);
  390.  
  391.     /* fmt is the number of the button that was selected in the format group */
  392.     if (fmt < 0) return ObjFalse; /* no choice made */
  393.     else if (fmt >= ListCount(fileReaders)) /* choice was "none" */
  394.     {
  395.         for (i=0; i<n; ++i) /* clear FORMAT and READER, leave filetype same */
  396.         {
  397.             theFile = GetListElem(list, i);
  398.             theIcon = GetVar(theFile, REPICON);
  399.             SetVar(theFile, READER, NULLOBJ);
  400.             SetVar(theIcon, FORMAT, NULLOBJ);
  401.             ImInvalid(theIcon);    /* cause redraw */
  402.         }
  403.     }
  404.     else
  405.     {
  406.         for (i=0; i<n; ++i)
  407.         {
  408.             theFile = GetListElem(list, i);
  409.             theRdr = GetListElem(fileReaders, fmt);
  410.             SetVar(theFile, READER, theRdr);
  411.             ChangeFileType(theFile, DATAFILE);
  412.             SetVar(GetVar(theFile, REPICON), FORMAT, 
  413.                    GetVar(theRdr, NAME));
  414.             theIcon = GetVar(theFile, REPICON);
  415.             ImInvalid(theIcon);    /* cause redraw */
  416.         }
  417.     }
  418.     return ObjTrue;
  419. }
  420.  
  421. /* ChangeFileType routine is somewhat obsolete since we eliminated the Set File Type command.
  422.     It is used in one place for Set File Format (in OKFormat above) just to change
  423.     a file's type to DATA. I kept the general form in case needed later. JL */
  424. #ifdef PROTO
  425. static void ChangeFileType(ObjPtr theFile, int newType)
  426. #else
  427. static void ChangeFileType(theFile, newType)
  428. ObjPtr theFile;
  429. int newType;
  430. #endif
  431. {
  432.     ObjPtr theIcon, theCorral, fileLists;
  433.     int oldType;
  434.  
  435.     oldType = GetInt(GetVar(theFile, FILETYPE));
  436.     if (oldType == newType) return;
  437.  
  438.     theIcon = GetVar(theFile, REPICON);
  439.     theCorral = GetVar(theIcon, PARENT);
  440.     fileLists = GetVar(theCorral, FILELIST);
  441.  
  442.     /* take file off old type list, add to new type list */
  443.     DeleteFromList(GetListElem(fileLists, oldType), theFile);
  444.     PrefixList(GetListElem(fileLists, newType), theFile);
  445.  
  446.     /* change the file type in file and icon */
  447.     SetVar(theFile, FILETYPE, NewInt(newType));
  448.     SetVar(theIcon, FILETYPE, NewInt(newType));
  449.  
  450.     /* change the icon */
  451.     SetVar(theIcon, WHICHICON, NewInt(fileIcon[newType]));
  452.  
  453.     if (newType == DATAFILE) /* just in case a file was changed from data, then back */
  454.     {
  455.         char *ext, *name;
  456.         ObjPtr theRdr;
  457.  
  458.         name = GetString(GetVar(theFile, NAME));
  459.         ext = strrchr(name, '.');
  460.         if (ext++ && (theRdr = FindExtensionReader(ext) ))
  461.         {
  462.             /* known data file format */
  463.             SetVar(theFile, READER, theRdr);
  464.             SetVar(theIcon, FORMAT, GetVar(theRdr, NAME));
  465.         }
  466.     }
  467.     else /* clear format in icon and file */
  468.     {
  469.         SetVar(theFile, READER, NULLOBJ);
  470.         SetVar(theIcon, FORMAT, NULLOBJ);
  471.     }
  472.     return;
  473. }
  474.  
  475. /******************************************************************** SHOW INFO */
  476. void ProcessShowInfo(void)
  477. {
  478.     WinInfoPtr infoWin;
  479.     ObjPtr textbox, thePath, list, theString;
  480.     char *path;
  481.     int i;
  482.  
  483.     path = GetString(thePath = GetVar(GetListElem(aList, 0), PATH));
  484.  
  485.     if (chdir(path) != 0)
  486.     {
  487.         ReportError("ProcessShowInfo", "Could not change directory");
  488.         return;
  489.     }
  490.  
  491.     /* get the info window */
  492.     theString = NewString("File Info");
  493.     infoWin = GetDialog((WinInfoPtr) NULLOBJ, theString, "File Info",
  494.         INFOWIDTH, INFOHEIGHT, INFOWIDTH, INFOHEIGHT, WINUI + WINFIXEDSIZE);
  495.     if (textbox = GetVar((ObjPtr) infoWin, REPOBJ)) /* dialog exists */
  496.     {
  497.         ThingListPtr p;
  498.         ObjPtr theFile, field, contents;
  499.         char *fileName;
  500.         int x, itemWid;
  501.     
  502.         /* pop info window */
  503.         PopWindow(infoWin);
  504.         SetVar(textbox, VALUE, thePath);
  505.         ImInvalid(textbox);
  506.  
  507.         /* put in file info textbox for each file on the list */
  508.         field = GetVar((ObjPtr) infoWin, FIELD);
  509.         SetVar(field, CONTENTS, contents = NewList());
  510.         p = LISTOF(aList);
  511.         x = MINORBORDER;
  512.         SetupFont(INFOFONT, INFOFONTSIZE); /* so we can check filename length */
  513.         while (p)
  514.         {
  515.             theFile = p -> thing;
  516.             fileName = GetString(GetVar(theFile, NAME));
  517.             itemWid = StrWidth(fileName);
  518.             if (itemWid < INFOITEMWID) itemWid = INFOITEMWID;
  519.             textbox = NewTextBox(x, x + itemWid, 
  520.                  -INFOFIELDHEIGHT + MINORBORDER, -MINORBORDER,
  521.                 PLAIN, "File Info", GetFileInfo(path, fileName));
  522.             PrefixList(contents, textbox);
  523.             SetVar(textbox, PARENT, field);
  524.             SetTextFont(textbox, INFOFONT);
  525.             SetTextSize(textbox, INFOFONTSIZE);
  526.             SetTextLineSpace(textbox, INFOITEMHT - INFOFONTSIZE);
  527.             p = p -> next;
  528.             x = x + itemWid + 2*MINORBORDER;
  529.         }
  530.         ScrollHome(field);
  531.         RecalcScroll(field);
  532.     }
  533.     else /* create info window */
  534.     {
  535.         ObjPtr field, panel, contents, button;
  536.         ThingListPtr p;
  537.         ObjPtr theFile;
  538.         char *fileName;
  539.         int x, itemWid;
  540.  
  541.         contents = GetVar((ObjPtr) infoWin, CONTENTS); /* contents of window */
  542.  
  543.         /* put in help string */
  544.         SetVar((ObjPtr) infoWin, HELPSTRING, NewString("This window shows directory \
  545. information for the selected file(s) in the file window. If more than one file was selected, \
  546. you can use the scrollbar at the bottom of the window to view information for each of them."));
  547.  
  548.         /* put in panel */
  549.         panel = NewPanel(greyPanelClass, 0, INFOWIDTH, 0, INFOHEIGHT);
  550.         PrefixList(contents, panel);
  551.         SetVar(panel, PARENT, (ObjPtr) infoWin);
  552.  
  553.         contents = GetVar(panel, CONTENTS); /* contents of panel */
  554.  
  555.         /* put path textbox at top */
  556.         textbox = NewTextBox(MINORBORDER, INFOWIDTH - MINORBORDER,
  557.                 INFOHEIGHT - MAJORBORDER - 2*INFOFONTSIZE - 2*DEFLINESPACE,
  558.                 INFOHEIGHT - MAJORBORDER, PLAIN, "Pathname", GetString(thePath));
  559.         SetVar(textbox, PARENT, panel);
  560.         PrefixList(contents, textbox);
  561.         SetTextFont(textbox, INFOFONT);
  562.         SetTextSize(textbox, INFOFONTSIZE);
  563.         SetTextAlign(textbox, RIGHTALIGN);
  564.         SetVar((ObjPtr) infoWin, REPOBJ, textbox); /* ref to by this routine */
  565.  
  566.         /* put in "fieldnames" textbox */
  567.         textbox = NewTextBox(MINORBORDER, MINORBORDER + INFONAMEWIDTH, 
  568.             MINORBORDER,
  569.             INFOHEIGHT-MAJORBORDER-2*INFOFONTSIZE-2*DEFLINESPACE-GAP-MINORBORDER-1,
  570.             PLAIN, "Fieldnames", 
  571.               "Name\nSize\nOwner\nMode\nModified");
  572.         SetVar(textbox, PARENT, panel);
  573.         PrefixList(contents, textbox);
  574.         SetTextFont(textbox, INFOFONT);
  575.         SetTextSize(textbox, INFOFONTSIZE);
  576.         SetTextAlign(textbox, RIGHTALIGN);
  577.         SetTextLineSpace(textbox, INFOITEMHT-INFOFONTSIZE);
  578.  
  579.         /* put in field for info text boxes */
  580.         field = NewControlField(2*MINORBORDER + INFONAMEWIDTH, INFOWIDTH - MINORBORDER,
  581.             MINORBORDER, MINORBORDER + INFOFIELDHEIGHT + BARWIDTH, 
  582.             "Info Field", OBJECTSFROMTOP + BARBOTTOM);
  583.         SetVar(field, BACKGROUND, NewInt(UIGRAY75));
  584.         SetVar(field, BORDERTYPE, NewInt(1));
  585.         SetVar(field, PARENT, panel);
  586.         PrefixList(contents, field);
  587.         SetVar(field, CONTENTS, contents = NewList());
  588.         SetVar((ObjPtr) infoWin, FIELD, field);
  589.  
  590.         /* put in file info textbox for each file on the list */
  591.         p = LISTOF(aList);
  592.         x = MINORBORDER;
  593.         SetupFont(INFOFONT, INFOFONTSIZE); /* so we can check filename length */
  594.         while (p)
  595.         {
  596.             theFile = p -> thing;
  597.             fileName = GetString(GetVar(theFile, NAME));
  598.             itemWid = StrWidth(fileName);
  599.             if (itemWid < INFOITEMWID) itemWid = INFOITEMWID;
  600.             textbox = NewTextBox(x, x + itemWid, 
  601.                  -INFOFIELDHEIGHT + MINORBORDER, -MINORBORDER,
  602.                 PLAIN, "File Info", GetFileInfo(path, fileName));
  603.             PrefixList(contents, textbox);
  604.             SetVar(textbox, PARENT, field);
  605.             SetTextFont(textbox, INFOFONT);
  606.             SetTextSize(textbox, INFOFONTSIZE);
  607.             SetTextLineSpace(textbox, INFOITEMHT - INFOFONTSIZE);
  608.             p = p -> next;
  609.             x = x + itemWid + 2*MINORBORDER;
  610.         }
  611.         RecalcScroll(field);
  612.     }
  613.     if (logging) InhibitLogging(false);
  614.     chdir(dirSave); /* return to original working directory */
  615.     return;
  616. }
  617.  
  618. #ifdef PROTO
  619. static char *GetFileInfo(char *path, char *fileName)
  620. #else
  621. static char *GetFileInfo(path, fileName)
  622. char *path, *fileName;
  623. #endif
  624. {
  625.     char *p = tempStr, *s, buf[20];
  626.     struct stat stbuf;
  627.     struct passwd *pwbuf;
  628.     struct tm *tmbuf;
  629.     short mode;
  630.  
  631.     s = fileName;
  632.     while (*p++ = *s++) ;
  633.     *(p - 1) = '\n';
  634.  
  635.     /* get file info */
  636.     if (stat(fileName, &stbuf) == -1) /* This happens! (eg, link to a bin, dead link) */
  637.     {
  638.         strcpy(p, "?\n?\n?\n?");
  639.     }
  640.     else
  641.     {
  642.         /* get size in K */
  643.         sprintf(buf,"%dK",(stbuf.st_size + 1023)/1024);
  644.         s = buf;
  645.         while (*p++ = *s++) ;
  646.         *(p - 1) = '\n';
  647.  
  648.         /* get owner name */
  649.         pwbuf = getpwuid(stbuf.st_uid);
  650.         if (pwbuf)
  651.         {
  652.             s = pwbuf -> pw_name;
  653.         }
  654.         else
  655.         {
  656.             s = "(unavailable)";
  657.         }
  658.         while (*p++ = *s++) ; /* copy name */
  659.         *(p - 1) = '\n';
  660.  
  661.         /* get mode bits */
  662.         mode = stbuf.st_mode;
  663.         *p++ = mode & S_IRUSR ? 'r' : '-';
  664.         *p++ = mode & S_IWUSR ? 'w' : '-';
  665.         *p++ = mode & S_IXUSR ? 'x' : '-';
  666.         *p++ = ' ';
  667.         *p++ = mode & S_IRGRP ? 'r' : '-';
  668.         *p++ = mode & S_IWGRP ? 'w' : '-';
  669.         *p++ = mode & S_IXGRP ? 'x' : '-';
  670.         *p++ = ' ';
  671.         *p++ = mode & S_IROTH ? 'r' : '-';
  672.         *p++ = mode & S_IWOTH ? 'w' : '-';
  673.         *p++ = mode & S_IXOTH ? 'x' : '-';
  674.         *p++ = '\n';
  675.  
  676.         /* get modified date */
  677.         tmbuf = localtime(&stbuf.st_mtime);
  678.         sprintf(buf,"%02d/%02d/%02d %02d:%02d\n", tmbuf->tm_mon + 1, tmbuf->tm_mday,
  679.             tmbuf->tm_year, tmbuf->tm_hour, tmbuf->tm_min);
  680.         s = buf;
  681.         while (*p = *s++) ++p;
  682.     }
  683.     return tempStr;
  684. }
  685.  
  686. /********************************************************************* FILE FORMAT DIALOG
  687. *    Puts up a dialog for selecting data file format.
  688. *    The OKRoutine is called with the selected format and list of files:
  689. *
  690. *        void OKRoutine(int fmt, ObjPtr list)
  691. */
  692. #ifdef PROTO
  693. static void FileFormatDialog(FuncTyp OKRoutine)
  694. #else
  695. static void FileFormatDialog(OKRoutine)
  696. FuncTyp OKRoutine;
  697. #endif
  698. {
  699.     WinInfoPtr theDialog;
  700.     ObjPtr panel, alertPanel, contents, promptBox, radioBtn, cancelBtn, okBtn;
  701.     ObjPtr thePrompt, radioGroup, keyList, fileReaders;
  702.     int row, col, nRows, nCols, totWid, totHt;
  703.     int n, nBtns;
  704.  
  705.     /* make a list of all the file readers */
  706.     keyList = NewList();
  707.     PostfixList(keyList, NewSymbol(CLASSID));
  708.     PostfixList(keyList, NewInt(CLASS_FILEREADER));
  709.     fileReaders = SearchDatabase(keyList);
  710.  
  711.     nBtns = ListCount(fileReaders) + 1;
  712.  
  713.     /* first compute sizes from the number of buttons */
  714.     /* number of buttons is one more than number of formats to allow for "none" */
  715.     if (nBtns < 11) nCols = 2, nRows = (nBtns + 1)/2;
  716.     else if (nBtns < 25) nCols = 3, nRows = (nBtns + 2)/3;
  717.     else nCols = 4, nRows = (nBtns + 3)/4;
  718.     totWid = 2*SIDEMARGIN + nCols*RADIOWID + (nCols - 1)*GAP;
  719.     totHt = BOTMARGIN + OKBTNHT + 2*INTERSPACE + nRows*CHECKBOXHEIGHT + (nRows - 1)*GAP
  720.         + PROMPTTEXTSIZE + TOPMARGIN;
  721.  
  722.     /* see if dialog exists */
  723.     if (!selWinInfo) return;
  724.     thePrompt = NewString("Set file format to:");
  725.     theDialog = GetDialog(selWinInfo, thePrompt, "Set Data Format",
  726.         totWid, totHt, totWid, totHt, 
  727.         WINUI + WINFIXEDSIZE + WINCENTERED + WINNOFRAME);
  728.     if(!theDialog) return;
  729.  
  730.     if (GetVar((ObjPtr) theDialog, REPOBJ)) /* dialog exists */
  731.     {
  732.         /* pop the dialog */
  733.         PopWindow(theDialog);
  734.     }
  735.     else /* make the dialog box */
  736.     {
  737.         ThingListPtr runner;
  738.  
  739.         SetVar((ObjPtr) theDialog, REPOBJ, thePrompt); /* mark dialog */
  740.         contents = GetVar((ObjPtr) theDialog, CONTENTS); /* contents of window */
  741.         SetVar((ObjPtr) theDialog, HELPSTRING, NewString("This window shows \
  742. the data file formats recognized by this version of SciAn. Click on the proper format \
  743. for the selected files and press the OK button. For more information, see the section \
  744. on data file formats in the SciAn User's manual."));
  745.  
  746.         /* put in panel */
  747.         panel = NewPanel(greyPanelClass, 0, totWid, 0, totHt);
  748.         PrefixList(contents, panel);
  749.         SetVar(panel, PARENT, (ObjPtr) theDialog);
  750.  
  751.         contents = GetVar(panel, CONTENTS); /* contents of panel */
  752.  
  753.         /* put in pretty panel */
  754.         alertPanel = NewAlertPanel(0, totWid, 0, totHt, "Fmt Panel");
  755.         PrefixList(contents, alertPanel);
  756.         SetVar(alertPanel, PARENT, panel);
  757.  
  758.         /* put in prompt */
  759.         promptBox = NewTextBox(SIDEMARGIN, totWid - SIDEMARGIN,
  760.                 totHt - TOPMARGIN - PROMPTTEXTSIZE, totHt - TOPMARGIN,
  761.                 PLAIN, "Prompt Box", GetString(thePrompt));
  762.         PrefixList(contents, promptBox);
  763.         SetVar(promptBox, PARENT, panel);
  764.         SetVar(promptBox, UIFONT, NewInt(PROMPTTEXTFONT));
  765.         SetTextColor(promptBox, PROMPTTEXTCOLOR);
  766.  
  767.         /* put in the bottom buttons */
  768.         cancelBtn = NewButton(totWid - SIDEMARGIN - 2*OKBTNWID - GAP,
  769.                 totWid - SIDEMARGIN - OKBTNWID - GAP,
  770.                 BOTMARGIN, BOTMARGIN + OKBTNHT, "Cancel");
  771.         PrefixList(contents, cancelBtn);
  772.         SetVar(cancelBtn, PARENT, panel);
  773.         SetMethod(cancelBtn, CHANGEDVALUE, CancelDialog);
  774.         SetVar(cancelBtn, HELPSTRING, NewString("Pressing this button \
  775. will cancel this dialog window without changing the format of the selected file(s)."));
  776.  
  777.         okBtn = NewButton(totWid - SIDEMARGIN - OKBTNWID,
  778.                 totWid - SIDEMARGIN,
  779.                 BOTMARGIN, BOTMARGIN + OKBTNHT, "OK");
  780.         PrefixList(contents, okBtn);
  781.         SetVar(okBtn, PARENT, panel);
  782.         SetMethod(okBtn, OKMETHOD, OKRoutine); /* for ref by OKDialog */
  783.         SetMethod(okBtn, CHANGEDVALUE, OKDialog);
  784.         SetVar(okBtn, HELPSTRING, NewString("Pressing this button \
  785. will dismiss this dialog window and set the format of the selected file(s)."));
  786.         SetVar(okBtn, REPOBJ, (ObjPtr) theDialog);
  787.  
  788.         /* oh, yeah -- guess we need a few radio buttons */
  789.         radioGroup = NewRadioButtonGroup("Data Format");
  790.         PrefixList(contents, radioGroup);
  791.         SetVar(radioGroup, PARENT, panel);
  792.         runner = LISTOF(fileReaders);
  793.         for (n=0, row=nRows-1; row>=0 && runner; --row)
  794.         {
  795.             for (col = 0; col<nCols && runner; ++col)
  796.             {
  797.                 ObjPtr theName;
  798.                 theName = GetVar(runner -> thing, NAME);
  799.                 radioBtn = NewRadioButton(
  800.                     SIDEMARGIN + col*(RADIOWID + GAP),
  801.                     SIDEMARGIN + (col+1)*RADIOWID + col*GAP,
  802.                     BOTPART + row*(CHECKBOXHEIGHT + GAP),
  803.                     BOTPART + (row+1)*CHECKBOXHEIGHT + row*GAP,
  804.                     theName ? GetString(theName) : "");
  805.                 AddRadioButton(radioGroup, radioBtn);
  806.                 runner = runner -> next; 
  807.             }
  808.         }
  809.         /* now add "none" button */
  810.         row = 0; col = nCols - 1;
  811.         radioBtn = NewRadioButton(
  812.             SIDEMARGIN + col*(RADIOWID + GAP),
  813.             SIDEMARGIN + (col+1)*RADIOWID + col*GAP,
  814.             BOTPART + row*(CHECKBOXHEIGHT + GAP),
  815.             BOTPART + (row+1)*CHECKBOXHEIGHT + row*GAP,
  816.             "NONE");
  817.         AddRadioButton(radioGroup, radioBtn);
  818.         
  819.         SetVar(okBtn, DATA, radioGroup); /* ref by OKDialog */
  820.     }
  821.     return;
  822. }
  823.  
  824. static ObjPtr OKDialog(btn)
  825. ObjPtr btn;
  826. {
  827.     FuncTyp OKRtn;
  828.     ObjPtr list, dialog;
  829.     int val;
  830.  
  831.     list = GetVar(GetVar(btn, REPOBJ), FILELIST); /* btn's REPOBJ is dialog */
  832.     val = GetInt(GetVar(GetVar(btn, DATA), VALUE));
  833.     OKRtn = GetMethod(btn, OKMETHOD);
  834.  
  835.     DeferClose();
  836.     OKRtn(val, list);
  837.     return ObjTrue;
  838. }
  839.  
  840. static ObjPtr CancelDialog(btn)
  841. ObjPtr btn;
  842. {
  843.     DeferClose();
  844.     return ObjFalse;
  845. }
  846.  
  847. /******************************************************************* GET FILE WINDOW */
  848. #ifdef PROTO
  849. void GetFileWindow(char *dirName)
  850. #else
  851. void GetFileWindow(dirName)
  852. char *dirName;
  853. #endif
  854.  
  855. /* Create/pop Files dialog */
  856. {
  857.     WinInfoPtr fileWin;
  858.     ObjPtr panel, contents, corral, thePath;
  859.     ObjPtr btn, btnGroup;
  860.     int btnWid;
  861.  
  862.     /* get the dialog window */
  863.     thePath = NewString(dirName);
  864.     fileWin = GetDialog((WinInfoPtr) NULLOBJ, thePath, dirName,
  865.         FILESWIDTH, FILESHEIGHT, SCRWIDTH, SCRHEIGHT, WINUI);
  866.     if(!fileWin) return;
  867.  
  868.  
  869.     if (GetVar((ObjPtr) fileWin, PATH)) /* dialog exists */
  870.     {
  871.         /* pop files dialog */
  872.         PopWindow(fileWin);
  873.     }
  874.     else /* create file window */
  875.     {
  876.         InhibitLogging(true);
  877.         SetVar((ObjPtr) fileWin, PATH, thePath); /* ref by this routine */
  878.         contents = GetVar((ObjPtr) fileWin, CONTENTS); /* contents of window */
  879.  
  880.         /* put in help string */
  881.         SetVar((ObjPtr) fileWin, HELPSTRING, NewString("This window shows the files \
  882. and sub-directories located in the directory given by the window's title. The files appear as \
  883. icons corresponding to file type; sub-directories appear as folders. To open a file or \
  884. folder, select its icon and press the Open button, or simply double click on it."));
  885.  
  886.         /* put in panel */
  887.         panel = NewPanel(greyPanelClass, 0, FILESWIDTH, 0, FILESHEIGHT);
  888.         PrefixList(contents, panel);
  889.         SetVar(panel, PARENT, (ObjPtr) fileWin);
  890.         SetVar(panel, STICKINESS, NewInt(STICKYALL));
  891.  
  892.         contents = GetVar(panel, CONTENTS); /* contents of panel */
  893.  
  894.         /* put in icon corral */
  895.         corral = NewIconCorral(NULLOBJ, MINORBORDER, 
  896.                 FILESWIDTH - MINORBORDER, TITLEBOXTOP + MINORBORDER + OKBTNHT,
  897.                 FILESHEIGHT - (TITLEBOXTOP + MINORBORDER + PARENTBTNHT),
  898.                 OBJECTSFROMTOP + BARRIGHT + BARBOTTOM);
  899.         SetVar(corral, STICKINESS, NewInt(STICKYALL));
  900.         PrefixList(contents, corral);
  901.         SetVar(corral, PARENT, panel);
  902.         SetVar(corral, PATH, thePath);
  903.         SetVar(corral, SELECTOR, NewInt(DEFAULTFILTER)); /* file selector bits */
  904.         SetMethod(corral, SHOWFILES, ShowFiles);
  905.         SetMethod(corral, DROPINCONTENTS, DropInFileWin);
  906.  
  907.         /* put in title box for filter buttons */
  908.         btn = NewTitleBox(MINORBORDER, MINORBORDER + FILTERBTNWID + 2*SMALLGAP,
  909.             FILESHEIGHT - TITLEBOXTOP - PARENTBTNHT, FILESHEIGHT - 4, "Files");
  910.         PrefixList(contents, btn);
  911.         SetVar(btn, PARENT, panel);
  912.         SetVar(btn, STICKINESS, NewInt(STICKYTOP + STICKYLEFT));
  913.  
  914.         /* put in file filter radio group */
  915.         btnGroup = NewRadioButtonGroup("File Filter");
  916.         SetVar(btnGroup, PARENT, panel);
  917.         PrefixList(contents, btnGroup);
  918.         SetVar(btnGroup, CORRAL, corral);
  919.         SetVar(btnGroup, STICKINESS, NewInt(STICKYTOP + STICKYLEFT));
  920.         SetVar(btnGroup, HELPSTRING, NewString("These buttons determine which file types \
  921. to show in the File Window. (Folders are always shown.) If the top button is checked, only SciAn \
  922. data, log, and palette files are shown; the files must have proper filename \
  923. extensions to be recognized by SciAn. If the bottom button is checked, all files are shown."));
  924.  
  925.         btn = NewRadioButton(MINORBORDER + SMALLGAP, 
  926.           MINORBORDER + SMALLGAP + FILTERBTNWID,
  927.           FILESHEIGHT - TITLEBOXTOP - PARENTBTNHT + SMALLGAP + CHECKBOXHEIGHT + CHECKBOXSPACING,
  928.           FILESHEIGHT - TITLEBOXTOP - PARENTBTNHT + SMALLGAP + 2*CHECKBOXHEIGHT + CHECKBOXSPACING,
  929.           "Show SciAn files only");
  930.         AddRadioButton(btnGroup, btn);
  931.         SetVar(btn, STICKINESS, NewInt(STICKYTOP + STICKYLEFT));
  932.         SetVar(btn, SELECTOR, NewInt(DEFAULTFILTER));
  933.  
  934.         btn = NewRadioButton(MINORBORDER + SMALLGAP, 
  935.             MINORBORDER + SMALLGAP + FILTERBTNWID,
  936.             FILESHEIGHT - TITLEBOXTOP - PARENTBTNHT + SMALLGAP,
  937.             FILESHEIGHT - TITLEBOXTOP - PARENTBTNHT + SMALLGAP + CHECKBOXHEIGHT,
  938.             "Show all files");
  939.         AddRadioButton(btnGroup, btn);
  940.         SetVar(btn, STICKINESS, NewInt(STICKYTOP + STICKYLEFT));
  941.         SetVar(btn, SELECTOR, NewInt(ALLFILES));
  942.         SetValue(btnGroup, NewInt(0)); /* make "Show SciAn files only" the default */
  943.         SetMethod(btnGroup, CHANGEDVALUE, NewFilter);
  944.  
  945.         /* put in parent button */
  946.         btn = NewIconLabeledButton(FILESWIDTH - MINORBORDER - PARENTBTNWID, 
  947.             FILESWIDTH - MINORBORDER, FILESHEIGHT - TITLEBOXTOP - PARENTBTNHT,
  948.             FILESHEIGHT - TITLEBOXTOP, ICONPARENT, UIWHITE, "Open Parent", BS_PLAIN);
  949.         SetVar(btn, STICKINESS, NewInt(STICKYTOP + STICKYRIGHT));
  950.         SetVar(btn, PARENT, panel);
  951.         SetVar(btn, LABEL, NewString("Open Parent"));
  952.         SetVar(btn, HELPSTRING, NewString("Pressing this button will \
  953. open a new file window at the next higher directory level. The directory of the current window \
  954. will appear as a folder in the new window."));
  955.         PrefixList(contents, btn);
  956.         MakeButtonToggled(btn, true); /* make parent button icon be lit up always */
  957.         SetValue(btn, NewInt(true));
  958.         MakeButtonToggled(btn, false);
  959.         SetVar(btn, PATH, thePath); /* ref by OpenParent */
  960.         SetMethod(btn, CHANGEDVALUE, DoParent);
  961.         SetMethod(btn, OPEN, OpenParent);
  962.  
  963.         /* put in action buttons */
  964.         btnWid = (FILESWIDTH - 2*MINORBORDER - 2*SMALLGAP)/3;
  965.         btn = NewFunctionButton(fileWin, MINORBORDER, MINORBORDER + btnWid,
  966.                 MINORBORDER, MINORBORDER + OKBTNHT, OF_OPEN);
  967.         if (btn)
  968.         {
  969.             SetVar(btn, PARENT, panel);
  970.             PrefixList(contents, btn);
  971.             SetVar(btn, STICKINESS, NewInt(STICKYLEFT + FLOATINGRIGHT));
  972.         }
  973.  
  974.         btn = NewFunctionButton(fileWin, MINORBORDER + btnWid + SMALLGAP, 
  975.         MINORBORDER + SMALLGAP + 2*btnWid,
  976.                 MINORBORDER, MINORBORDER + OKBTNHT,
  977.                 OF_SETFORMAT);
  978.         if (btn)
  979.         {
  980.             SetVar(btn, PARENT, panel);
  981.             PrefixList(contents, btn);
  982.             SetVar(btn, STICKINESS, NewInt(FLOATINGRIGHT + FLOATINGLEFT));
  983.         }
  984.  
  985.         btn = NewFunctionButton(fileWin, FILESWIDTH - MINORBORDER - btnWid, FILESWIDTH - MINORBORDER,
  986.                 MINORBORDER, MINORBORDER + OKBTNHT,
  987.                 OF_SHOWINFO);
  988.         if (btn)
  989.         {
  990.             SetVar(btn, PARENT, panel);
  991.             PrefixList(contents, btn);
  992.             SetVar(btn, STICKINESS, NewInt(FLOATINGLEFT + STICKYRIGHT));
  993.         }
  994.  
  995.         /* set up reference */
  996.         SetVar((ObjPtr) fileWin, CORRAL, corral); /* ref by this routine */
  997.  
  998.         /* now put in the file icons */
  999.         ReadDirectory(corral);
  1000.         ShowFiles(corral);
  1001.         InhibitLogging(false);
  1002.     }
  1003. }
  1004.  
  1005. #ifdef PROTO
  1006. ObjPtr IconHelp(ObjPtr icon, ObjPtr class)
  1007. #else
  1008. ObjPtr IconHelp(icon, class)
  1009. ObjPtr icon, class;
  1010. #endif
  1011. {
  1012.     int type = GetInt(GetVar(icon, FILETYPE));
  1013.  
  1014.     switch (type)
  1015.     {
  1016.         case DIRFILE:
  1017.             SetVar(class, HELPSTRING, NewString("This icon represents a sub-directory \
  1018. within the directory of this file window. Double clicking on the folder will open a file window \
  1019. for the sub-directory."));
  1020.             break;
  1021.  
  1022. #ifndef RELEASE
  1023.         case PALFILE:
  1024.             SetVar(class, HELPSTRING, NewString("This icon represents a palette file \
  1025. which has been saved by SciAn. For more information, ask Eric."));
  1026.             break;
  1027. #endif
  1028.             
  1029.         case DATAFILE:
  1030.             SetVar(class, HELPSTRING, NewString("\
  1031. This icon represents a data file with a format recognized by this version of SciAn. The \
  1032. name of the format is shown under the file name. \
  1033. Double clicking on this icon will read the file into the Datasets window."));
  1034.             break;
  1035.  
  1036.         case OTHFILE:
  1037.             SetVar(class, HELPSTRING, NewString("This icon represents a file whose type \
  1038. SciAn could not determine from the filename extension. If the file is a data file, you must \
  1039. identify the data format before SciAn can read the file. Select the file, press the Set \
  1040. Format button, and then select the proper format."));
  1041.             break;
  1042.  
  1043.         default:
  1044.             SetVar(class, HELPSTRING, NewString("This icon represents a file in the \
  1045. directory of this file window."));
  1046.             break;
  1047.     }
  1048.     return NULLOBJ;
  1049. }
  1050.  
  1051. /************************************************************************ READ DIRECTORY 
  1052. *    Reads directory of 'path' associated with given corral.
  1053. *    Creates file objects and sets parameters for them.
  1054. */
  1055. #ifdef PROTO
  1056. static Bool ReadDirectory(ObjPtr corral)
  1057. #else
  1058. static Bool ReadDirectory(corral)
  1059. ObjPtr corral;
  1060. #endif
  1061. {
  1062.     struct stat stbuf;
  1063.     int fd;
  1064. #ifdef DIRENT
  1065.     struct dirent *dp;
  1066. #else
  1067.     struct direct *dp;
  1068. #endif
  1069.     DIR *dirp;
  1070.     ObjPtr thePath, theFile;
  1071.     ObjPtr fileLists, sortedLists;
  1072.     int i, fileType;
  1073.     ObjPtr theRdr;
  1074.     char *path, *ext;
  1075.  
  1076.     /* this may take a while */
  1077.     LongOperation();
  1078.  
  1079.     thePath = GetVar(corral, PATH);
  1080.     if (thePath) path = GetString(thePath);
  1081.     else return false;
  1082.  
  1083.     if (chdir(path) != 0)
  1084.     {
  1085.         ReportError("ReadDirectory", "Error changing directory");
  1086.         return false;
  1087.     }
  1088.  
  1089.     /* open directory */
  1090.     if (!(dirp = opendir(path)))
  1091.     {
  1092.         ReportError("ReadDirectory", "Error opening directory");
  1093.         chdir(dirSave);
  1094.         return false;
  1095.     }
  1096.  
  1097.     /* set up master list and file type lists */
  1098.     fileLists = NewList();
  1099.     for (i=0; i<NFILETYPES; ++i) PrefixList(fileLists, NewList());
  1100.  
  1101.     /* read directory */
  1102.     while ((dp = readdir(dirp)) != NULL) /***/
  1103.     {
  1104.  
  1105.         if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) continue;
  1106.         stat(dp->d_name, &stbuf);
  1107.         if((stbuf.st_mode & S_IFMT) == S_IFLNK) continue; /*** must be a dead link? */
  1108.         if ((stbuf.st_mode & S_IFMT) == S_IFSOCK) continue; /* socket file */
  1109.  
  1110.         if (*dp->d_name == '.') continue; /* ignore dot files */
  1111.         ext = strrchr(dp->d_name, '.'); /* point to filename extension */
  1112.  
  1113.         /* make a file object */
  1114.         theFile = NewObject(fileClass, 0);
  1115.         SetVar(theFile, NAME, NewString(dp->d_name));
  1116.         SetVar(theFile, PATH, thePath);
  1117.  
  1118.         /* figure out file type */
  1119.         if((stbuf.st_mode & S_IFMT) == S_IFDIR)
  1120.         {
  1121.             /* entry is a directory */
  1122.             SetVar(theFile, FILETYPE, NewInt(DIRFILE));
  1123.             PrefixList(GetListElem(fileLists, DIRFILE), theFile);
  1124.         }
  1125.         else
  1126.         {
  1127.             /* check file extension to identify file type */
  1128.             if (ext++) /* skip dot */
  1129.             {
  1130.                 if (strcmp(ext, "o") == 0)
  1131.                 {
  1132.                     /* object file */
  1133.                     SetVar(theFile, FILETYPE, NewInt(OBJFILE));
  1134.                     PrefixList(GetListElem(fileLists, OBJFILE), theFile);
  1135.                 }
  1136.                 else if (strcmp(ext, "txt") == 0
  1137.                     || strcmp(ext, "c") == 0
  1138.                     || strcmp(ext, "h") == 0
  1139.                     || strcmp(ext, "f") == 0 )
  1140.                 {
  1141.                     /* text file */
  1142.                     SetVar(theFile, FILETYPE, NewInt(TEXTFILE));
  1143.                     PrefixList(GetListElem(fileLists, TEXTFILE), theFile);
  1144.                 }
  1145.                 else if ( theRdr = FindExtensionReader(ext) )
  1146.                 {
  1147.                     /* known data file extension */
  1148.                     SetVar(theFile, FILETYPE, NewInt(DATAFILE));
  1149.                     SetVar(theFile, READER, theRdr);
  1150.                     PrefixList(GetListElem(fileLists, DATAFILE), theFile);
  1151.                 }
  1152.                 else if (strcmp(ext, "log") == 0) /*** what should the ext be? */
  1153.                 {
  1154.                     /* script or log file */
  1155.                     SetVar(theFile, FILETYPE, NewInt(LOGFILE));
  1156.                     PrefixList(GetListElem(fileLists, LOGFILE), theFile);
  1157.                 }
  1158. #ifndef RELEASE
  1159.                 else if (strcmp(ext, "pal") == 0)
  1160.                 {
  1161.                     /* scian palette file */
  1162.                     SetVar(theFile, FILETYPE, NewInt(PALFILE));
  1163.                     PrefixList(GetListElem(fileLists, PALFILE), theFile);
  1164.                 }
  1165. #endif
  1166.                 else /* other file type */
  1167.                 {
  1168.                     SetVar(theFile, FILETYPE, NewInt(OTHFILE));
  1169.                     PrefixList(GetListElem(fileLists, OTHFILE), theFile);
  1170.                 }
  1171.             }
  1172.             else if (stbuf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
  1173.             {
  1174.                 /* entry is (probably) executable file */
  1175.                 SetVar(theFile, FILETYPE, NewInt(BINFILE));
  1176.                 PrefixList(GetListElem(fileLists, BINFILE), theFile);
  1177.             }
  1178.             else /* no dot, not executable: other file type */
  1179.             {
  1180.                 SetVar(theFile, FILETYPE, NewInt(OTHFILE));
  1181.                 PrefixList(GetListElem(fileLists, OTHFILE), theFile);
  1182.             }
  1183.         }
  1184.     }
  1185.     closedir(dirp);
  1186.  
  1187.     /* now sort the lists */
  1188.     sortedLists = NewList();
  1189.     for (i=0; i<NFILETYPES; ++i)
  1190.       PostfixList(sortedLists, SortListByStringVar(GetListElem(fileLists, i), NAME, false));
  1191.  
  1192.     SetVar(corral, FILELIST, sortedLists);
  1193.     chdir(dirSave);    /* return to original directory */
  1194.     return true;
  1195. }
  1196.  
  1197. /*********************************************************************** SHOW FILES
  1198. *    Puts the icons for the selected file types into the given corral.
  1199. */
  1200. static ObjPtr ShowFiles(corral)
  1201. ObjPtr corral;
  1202. {
  1203.     ObjPtr theFile, theIcon, theRdr, iconList;
  1204.     ObjPtr fileLists, theType, thePath;
  1205.     ObjPtr contents;
  1206.     int i, fileSelector, left, right, bottom, top, width;
  1207.     ThingListPtr p;
  1208.     FuncTyp ReScroll;
  1209.  
  1210.     /* this may take a while */
  1211.     LongOperation();
  1212.  
  1213.     fileSelector = GetInt(GetVar(corral, SELECTOR));
  1214.     fileLists = GetVar(corral, FILELIST);
  1215.     thePath = GetVar(corral, PATH);
  1216.  
  1217.     Get2DIntBounds(corral, &left, &right, &bottom, &top);
  1218.     width = right - left;
  1219.  
  1220.     SetVar(corral, CONTENTS, contents = NewList());
  1221.  
  1222.     /* now drop the selected filetype icons in the corral */
  1223.     for (i=0; i<NFILETYPES; ++i)
  1224.     {
  1225.         if (!(fileSelector & MASK(i))) continue;
  1226.         theType = NewInt(i);
  1227.         p = LISTOF(GetListElem(fileLists, i));
  1228.         while(p)
  1229.         {
  1230.             theFile = p -> thing;
  1231.             if (!(theIcon = GetVar(theFile, REPICON)))
  1232.             {
  1233.                 /* make icon for this file */
  1234.                 theIcon = NewIcon(0, 0, fileIcon[i], GetString(GetVar(theFile, NAME)));
  1235.                 SetVar(theFile, REPICON, theIcon);
  1236.                 SetVar(theIcon, REPOBJ, theFile);
  1237.                 SetVar(theIcon, PARENT, corral);
  1238.                 SetVar(theIcon, FILETYPE, theType);
  1239.                 SetVar(theIcon, PATH, thePath);
  1240.                 SetMethod(theIcon, MAKE1HELPSTRING, IconHelp);
  1241.  
  1242.                 if (i == DIRFILE)
  1243.                 {
  1244.                     SetMethod(theFile, OPEN, OpenFolder);
  1245.                 }
  1246.                 else
  1247.                 {
  1248.                     SetMethod(theFile, OPEN, OpenFile);
  1249.                     SetMethod(theFile, COLLECT, Collect);
  1250.                 }
  1251.  
  1252.                 if (theRdr = GetVar(theFile, READER)) /* put format name on icon */
  1253.                     SetVar(theIcon, FORMAT, GetVar(theRdr, NAME));
  1254.             }
  1255.             SetVar(theIcon, ICONLOC, NULLOBJ);
  1256.             PrefixList(contents, theIcon);
  1257.             p = p -> next;
  1258.         }
  1259.     }
  1260.     ScrollHome(corral);
  1261.     RecalcScroll(corral);
  1262.     ImInvalid(corral);    /* redraw if necessary */
  1263.     return ObjTrue; /* function is used as method */
  1264. }
  1265.  
  1266. static ObjPtr DropInFileWin(corral, icon, x, y)
  1267. ObjPtr corral, icon;
  1268. int x,y;
  1269. {
  1270. #if 0
  1271.     ObjPtr theFile, theFormat, theReader;
  1272.     int fileType;
  1273.     theFile = GetVar(icon, REPOBJ);
  1274.     if (theFile && IsFile(theFile)
  1275.     {
  1276.         fileType = GetInt(GetVar(theFile, FILETYPE));
  1277.         if (fileType == DIRFILE)
  1278.         {
  1279.             DoUniqueTask(ReportCantDoIt);
  1280.             return ObjFalse;
  1281.         }
  1282.         /* ok: to copy file need to make new icon and file objects, copy vars,
  1283.             and update fileList, corral contents */
  1284.         
  1285.     }
  1286. #else
  1287.     printf("Drop in file window not implemented.\n");
  1288. #endif
  1289.     return ObjFalse;
  1290. }
  1291.  
  1292. static ObjPtr DoParent(button)
  1293. ObjPtr button;
  1294. {
  1295.     DeferMessage(button, OPEN);
  1296.     return ObjTrue;
  1297. }
  1298.  
  1299. /* this is called only as a result of a deferred OPEN message to button */
  1300. static ObjPtr OpenParent(button)
  1301. ObjPtr button;
  1302. {
  1303.     char *s, dirName[MAXPATHLEN+1];;
  1304.  
  1305.     strncpy(dirName, GetString(GetVar(button, PATH)), MAXPATHLEN);
  1306.     dirName[MAXPATHLEN] = '\0'; /* ensure termination */
  1307.     s = strrchr(dirName, '/');
  1308.     if (s)
  1309.     {
  1310.         if (s > dirName)
  1311.         {
  1312.         *s = '\0';
  1313.         }
  1314.         else
  1315.         {
  1316.         *(s + 1) = '\0';
  1317.         }
  1318.         GetFileWindow(dirName);
  1319.     }
  1320.     return ObjTrue;
  1321. }
  1322.  
  1323. /*********************************************************************** NEW FILTER */
  1324. static ObjPtr NewFilter(b)
  1325. ObjPtr b;
  1326. {
  1327.     ObjPtr corral;
  1328.     int selector;
  1329.  
  1330.     corral = GetObjectVar("NewFilter", b, CORRAL);
  1331.     selector = GetInt(GetVar(b, VALUE)) ? ALLFILES : DEFAULTFILTER;
  1332.     SetVar(corral, SELECTOR, NewInt(selector));
  1333.     ShowFiles(corral);
  1334.     return ObjTrue;
  1335. }
  1336.  
  1337.  
  1338. /**************************************************************** OPEN FILE */
  1339. static ObjPtr OpenFile(theFile)
  1340. ObjPtr theFile;
  1341. /* opens (reads) one data file; returns ObjTrue if success or ObjFalse if failure */
  1342. {
  1343.     ObjPtr path, reader;
  1344.  
  1345.     reader = GetVar(theFile, READER);
  1346.     path = GetStringVar("OpenFile",theFile, PATH);
  1347.     if (!reader || !path || chdir(GetString(path)) != 0)
  1348.     {
  1349.     /***/    printf("error getting %s/%s\n",path,GetString(GetVar(theFile, NAME)));
  1350.         return ObjFalse;
  1351.     }
  1352.     LongOperation();
  1353.     ReadFormattedFile(reader, GetString(GetVar(theFile, NAME)));
  1354.  
  1355.     /* deselect after reading */
  1356.     /*** SelectIcon(GetVar(theFile, REPICON), false); ***/
  1357.  
  1358.     /*** take out when ObjFunction changed to call RestoreDir() ***/
  1359.     chdir(dirSave); /* change back to original working directory */
  1360.     return ObjTrue;
  1361. }
  1362.  
  1363. /* This routine is called only as a result of a deferred OPEN message */
  1364. static ObjPtr OpenFolder(theFile)
  1365. ObjPtr theFile;
  1366. {
  1367.     char *path, *name, dirName[MAXPATHLEN+1];
  1368.     DIR *dirp;
  1369.  
  1370.     path = GetString(GetVar(theFile, PATH));
  1371.     name = GetString(GetVar(theFile, NAME));
  1372.     if (strlen(path) + 1 + strlen(name) > MAXPATHLEN)
  1373.     {
  1374.         /* Oh, no! The dang pathname is too long! */
  1375.         ReportError("OpenFolder","Oh, no! The dang pathname is too long!");
  1376.         return ObjFalse;
  1377.     }
  1378.     strcpy(dirName, path);
  1379.         if (dirName[strlen(dirName) - 1] != '/')
  1380.     {
  1381.         strcat(dirName, "/");
  1382.     }
  1383.     strcat(dirName, name);
  1384.     dirName[MAXPATHLEN] = '\0';
  1385.  
  1386.     if(dirp = opendir(dirName)) /* good path? */
  1387.     {
  1388.         closedir(dirp);
  1389.         GetFileWindow(dirName);
  1390.         return ObjTrue;
  1391.     }
  1392.     else
  1393.     {
  1394.         /* Hey! There shouldn't be an error here! */
  1395.         ReportError("OpenFolder","Could not open the dang folder!");
  1396.         return ObjFalse;
  1397.     }
  1398. }
  1399.